package netmodule

import (
	"context"
	"fmt"
	"go_server/common"
	"go_server/components"
	"net"
	"strconv"
	"sync"
	"time"

	"github.com/astaxie/beego/logs"
)

type Server struct {
	Listener           net.Listener
	SessionGroup       sync.WaitGroup
	SessionMap         map[string]*common.SessionItem
	RWMtu              sync.RWMutex
	AcceptClose        chan interface{}
	OrderlyDealMsgFlag bool //处理模式(在tcpAccept.go的init函数中设置)--顺序处理或并发处理
}

var TcpServer *Server = nil
var exitChan chan interface{}

func init() {
	TcpServer = new(Server)
	TcpServer.AcceptClose = make(chan interface{}, 1)
	TcpServer.SessionMap = make(map[string]*common.SessionItem)
	TcpServer.OrderlyDealMsgFlag = false
	exitChan = make(chan interface{}, 1)
}
func closeAllSession() {
	//在执行该函数前，已经已经不再接收连接了

	keys := make([]string, 0, len(TcpServer.SessionMap))
	TcpServer.RWMtu.RLock()
	for k := range TcpServer.SessionMap {
		keys = append(keys, k)
	}
	TcpServer.RWMtu.RUnlock()
	for _, val := range keys {
		TcpServer.SessionMap[val].Conn.Close()
	}
}

func ExitProgram() {
	TcpServer.Listener.Close()
	close(exitChan)
	//close掉所有的连接
	closeAllSession()
	TcpServer.SessionGroup.Wait()
	logs.Debug("[tcpAccept.go:36]成功执行TcpServer.SessionGroup.Wait()")
	MsgQueueMapInstance.wg.Wait()
	logs.Debug("[tcpAccept.go:36]成功执行MsgQueueMapInstance.wg.Wait()")
	OutMsgQueueGroupInstance.OutWaitGroup.Wait()
	logs.Debug("[tcpAccept.go:36]成功执行OutMsgQueueGroupInstance.OutWaitGroup.Wait()")

}
func SetOrderlyDealMsgFlag(flag bool) {
	TcpServer.OrderlyDealMsgFlag = flag
}

func NewTcpServer() {
	//从配置文件中取相关配置
	address := "0.0.0.0:" + strconv.Itoa(components.TcpPort)
	listener, err := net.Listen("tcp", address)
	if err != nil {
		panic("listener 创建失败")
	}
	TcpServer.Listener = listener

	//创建相关队列
	NewMsgQueue()

	NewOutMsgQueue()

	//开启协程去监听
	go AcceptLoop()

	//开启踢人协程
	go kickGoRoutine()

	logs.Debug("成功启动服务器，监听的ip&port为:", address)
	fmt.Println("成功启动服务器，监听的ip&port为:", address)

}

func doingAccept() error {
	con, err := TcpServer.Listener.Accept()
	if err != nil {
		logs.Error("[tcpAccept.go:57]:Accept error---" + err.Error())
		return common.ErrAccept
	}

	//去创建session用于管理连接---同一个包不需要导入使用
	NewSessionItem := CreateSessionItem(con)

	TcpServer.RWMtu.Lock()
	TcpServer.SessionMap[NewSessionItem.Uuid] = NewSessionItem
	TcpServer.RWMtu.Unlock()
	//然后开启协程去循环读取
	TcpServer.SessionGroup.Add(1)
	go RecvLoop(NewSessionItem)
	logs.Debug("[tcpAccept.go:81]成功接收一个连接，对端信息为：", con.RemoteAddr().String())

	return nil
}

func AcceptLoop() {

	defer func() {
		//资源清理相关
		close(TcpServer.AcceptClose)

	}()

	for {
		select {
		case <-exitChan:
			logs.Debug("[tcpAccept.go:98]成功收到exitChan")
			return
		default:
			if err := doingAccept(); err != nil {
				return
			}
		}

	}

}

func checkOverTime() {

	keys := make([]string, 0, len(TcpServer.SessionMap))
	for k := range TcpServer.SessionMap {
		keys = append(keys, k)
	}
	now := time.Now().Unix()
	for _, value := range keys {
		if session, ok := TcpServer.SessionMap[value]; ok {
			if session.AliveTime+int64(components.OverTime) < now {
				session.Conn.Close() //超时关闭
			}
		}
	}

}

// 踢人协程
func kickGoRoutine() {
	//需要定点去获取key值---这可能出现异常，加锁吧
	for {
		C, cancel := context.WithTimeout(context.Background(), time.Duration(components.TickKickTime)*time.Second)
		select {
		case <-C.Done():
			checkOverTime()
			//然后开始检查
			cancel()
		case <-TcpServer.AcceptClose:
			cancel()
			return
		}

	}

}
